'use strict';
let PDFDocment = require('pdfkit');
let Enumerable = require('linq');
let BaseStyleRender = require('./BaseStyleRender');

/**
 *主从表数据源样式渲染
 *
 * @class MasterDetailStyleRender
 * @extends {BaseStyleRender}
 */
class MasterDetailStyleRender extends BaseStyleRender {
    /**
     *Creates an instance of MasterDetailStyleRender.
     * @param {*} data
     * @param {*} style
     * @memberof MasterDetailStyleRender
     */
    constructor(data, style) {
        super(data, style);
        this._itemCounters = [];
        this._groupData();
    }

    /**
     *数组分组
     *
     * @memberof MasterDetailStyleRender
     */
    _groupData() {
        let data = this._data;
        const masterDetailKeyFields = data.masterDetailKeyFields.split(',');
        const detailFieldKey1 = masterDetailKeyFields[0];
        const detailFieldKey = masterDetailKeyFields[1];
        this._detailFieldKey = detailFieldKey;
        Enumerable.from(data.detailData.itemList).forEach(item => {
            if (item.items && Array.isArray(item.items)) return;
            item.items = Enumerable.from(data.detailData1.itemList).where(i => i[detailFieldKey1] === item[detailFieldKey]).toArray();
        });
    }

    /**
     *获取当前样式
     *
     * @param {*} tempData
     * @returns
     * @memberof BaseStyleRender
     */
    _getCurrentStyle(tempData) {
        this._itemIndex++;
        let pageSetting = this._pageSetting;
        var addHeight = pageSetting.height / pageSetting.reportCount * (this._itemIndex % pageSetting.reportCount);
        var style = this._deepCopy(this._style);
        if (this._itemIndex !== 0) {
            if (addHeight !== 0) {
                Enumerable.from(style.controls.texts).forEach(text => (text.rect.top += addHeight));
                Enumerable.from(style.controls.tables).forEach(table => (table.top += addHeight));
            }
            if ((pageSetting.reportCount === 1 &&
                    this._itemIndex !== 0) ||
                (this._itemIndex > pageSetting.reportCount - 1 &&
                    this._itemIndex % pageSetting.reportCount === 0)
            ) {
                this._doc.addPage();
                this._pageNum++;
            }
        }
        if (pageSetting.showPageNum) {
            let pageNumText = Enumerable.from(style.controls.texts).firstOrDefault(text => text.name === 'pageNum');
            let itemPage = Enumerable.from(this._itemPages).firstOrDefault(item => item.pageNum === this._pageNum);
            let key = tempData.data[this._detailFieldKey];
            if (itemPage) {
                itemPage.items.push({
                    key,
                    text: pageNumText,
                });
            } else {
                this._itemPages.push({
                    pageIndex: this._pageNum - 1,
                    items: [{
                        key,
                        text: pageNumText,
                    }],
                });
            }
            let itemCounter = Enumerable.from(this._itemCounters).firstOrDefault(item => item.key === key);
            if (itemCounter) {
                itemCounter.count++;
            } else {
                this._itemCounters.push({
                    key,
                    count: 1,
                    num: 1
                });
            }
        }
        return style;
    }

    /**
     *渲染页码
     *
     * @memberof BaseStyleRender
     */
    _renderPageNum() {
        if (!this._pageSetting.showPageNum) return;
        let pageCount = this._itemIndex + 1;
        let num = 0;
        Enumerable.from(this._itemPages).forEach(itemPage => {
            this._doc.switchToPage(itemPage.pageIndex);
            Enumerable.from(itemPage.items).forEach(item => {
                let itemCounter = Enumerable.from(this._itemCounters).firstOrDefault(i => i.key === item.key);
                let text = item.text;
                let value = text.text.replace('@num', itemCounter.num).replace("@count", itemCounter.count);
                itemCounter.num++;
                this._renderText(value, {
                    left: text.rect.left,
                    top: text.rect.top,
                    width: text.rect.width,
                    align: text.align,
                    name: text.font.name,
                    size: text.font.size
                });
            });
        });
    }

    _render() {
        let data = this._data;
        Enumerable.from(data.detailData.itemList).forEach(item => {
            this._renderControls({
                data: item,
            });
        });
        this._renderPageNum();
    }

    _renderControls(tempData) {
        let style = this._getCurrentStyle(tempData);
        Enumerable.from(style.controls.tables).forEach(table => {
            this._renderTable(table, tempData, style.controls.texts);
        });
    }

    _renderTable(table, tempData1, texts) {
        let tempData = this._getTempData(table, tempData1, texts);
        this._renderHeaderRow(tempData);
        for (let i = 0; i < table.rows.length; i++) {
            let row = table.rows[i];
            if (row.isFixed || row.isHeader) continue;
            if (this._isDetailFieldRow(row)) {
                //渲染数据行
                let paging = this._renderDetailRow(row, tempData);
                if (paging) return;
                continue;
            }
            //渲染其他行
            this._renderRow(row, tempData);
        }
        // 渲染固定行
        Enumerable.from(tempData.fixedRows).forEach(row => this._renderRow(row, tempData));
        // 渲染Texts
        this._renderTexts(tempData);
    }

    _getTempData(table, tempData1, texts) {
        let headerRow = Enumerable.from(table.rows).firstOrDefault(row => row.isHeader);
        let fixedRows = Enumerable.from(table.rows).where(row => row.isFixed).toArray();
        let fixedHeight = Enumerable.from(fixedRows).sum(row => this._getRowHeight(row, null, null, tempData1));
        let tempData = {
            texts,
            headerRow,
            fixedRows,
            fixedHeight,
            renderHeight: 0,
            left: table.left,
            top: table.top,
            height: table.height,
            isFixedRowHeight: table.isFixedRowHeight || false,
            fixedRowHeight: table.fixedRowHeight || 0,
            isFixedRowCount: table.isFixedRowCount || false,
            fixedRowCount: table.fixedRowCount || 0,
            data: tempData1.data,
        };
        return tempData;
    }

    _renderDetailRow(row, tempData) {
        let pageSetting = this._pageSetting;
        let detailData = this._deepCopy(tempData.data.items);
        let nextRowHeight = 0;
        for (let i = 0; i < detailData.length; i++) {
            let item = detailData[i];
            let rowHeight = nextRowHeight || this._getRowHeight(row, item, false, tempData);
            this._renderRow(row, tempData, rowHeight);
            tempData.data.items.splice(0, 1);
            if (tempData.isFixedRowCount) {
                if (i === tempData.fixedRowCount - 1 && tempData.data.items.length !== 0) {
                    // 渲染固定行
                    Enumerable.from(tempData.fixedRows).forEach(row => this._renderRow(row, tempData));
                    // 渲染Texts
                    this._renderTexts(tempData);
                    // 渲染剩余数据
                    this._renderControls(tempData);
                    return true;
                }
                // 如果渲染完毕,判断行数是否达到固定行数,若未达到则渲染空白行
                let count = tempData.fixedRowCount - (i + 1);
                if (tempData.data.items.length === 0 && count !== 0) {
                    for (let j = 0; j < count; j++) {
                        this._renderRow(row, tempData, tempData.fixedRowHeight, true);
                    }
                }
                continue;
            }
            if (tempData.data.items.length === 0) break;
            nextRowHeight = this._getRowHeight(row, detailData[i + 1], false, tempData);
            if (tempData.height - tempData.renderHeight - tempData.fixedHeight < nextRowHeight) {
                // 渲染固定行
                Enumerable.from(tempData.fixedRows).forEach(row => this._renderRow(row, tempData));
                // 渲染Texts
                this._renderTexts(tempData);
                // 渲染剩余数据
                this._renderControls(tempData);
                return true;
            }
        }
        return false;
    }

    _getRowHeight(row, item, getbytext, tempData) {
        let pageSetting = this._pageSetting;
        let rowHeight = pageSetting.fontSize + 9;
        let fixedRow = tempData && tempData.isFixedRowHeight;
        Enumerable.from(row.cells).forEach(cell => {
            cell.showtext = getbytext ? cell.text :
                (item && this._isDetailField(cell) ?
                    this._getDetailFieldValue(cell, item) :
                    this._getMasterFieldValue(cell, tempData));
            // 合并行和固定行高 不参与行高计算
            if ((cell.detailField && cell.detailField.mergeSameRow) || fixedRow) return;
            let height =
                this._getTextHeight(cell.showtext, {
                    width: cell.width - 10,
                    align: cell.align,
                    size: cell.font.size,
                }) + 9;
            if (height > rowHeight) rowHeight = height;
        });
        return fixedRow ? tempData.fixedRowHeight : rowHeight;
    }

    _getDetailField(control) {
        let data = this._data;
        let detailName = this._getDetailFieldName(control);
        if (detailName == '') return null;
        let detailField = Enumerable.from(data.detailFields1).firstOrDefault(field => field.name == detailName);
        control.detailField = detailField;
        return detailField;
    }

    _renderHeaderRow(tempData) {
        let row = tempData.headerRow;
        let rowHeight = tempData.tableHeaderHeight || this._getRowHeight(row, null, true);
        tempData.tableHeaderHeight = rowHeight;
        this._renderRow(row, tempData, rowHeight);
    }

    _renderRow(row, tempData, rowHeight, isEmpty) {
        let left = tempData.left;
        rowHeight = rowHeight || this._getRowHeight(row, null, null, tempData);
        Enumerable.from(row.cells).forEach(cell => {
            let showtext = isEmpty ? '' : cell.showtext;
            this._renderTextAndRect(showtext, {
                left,
                top: tempData.top,
                width: cell.width,
                height: rowHeight,
                align: cell.align || 'left',
                name: cell.font.name || 'normal',
                isFixedRowHeight: tempData.isFixedRowHeight,
                size: cell.font.size,
                valign: cell.valign,
            });
            left += cell.width;
        });
        tempData.renderHeight += rowHeight;
        tempData.top += rowHeight;
    }

    _getMasterField(control) {
        let data = this._data;
        let masterField = new Object();
        Enumerable.from(data.detailFields).forEach(item => {
            if (item.name !== control.name) return;
            masterField.name = item.name;
            masterField.caption = item.name;
            masterField.dataField = item.dataField;
            masterField.value = item.value;
        });
        return masterField;
    }
}

exports = module.exports = MasterDetailStyleRender;